package service

import (
	"admin100/app/dao"
	"admin100/app/dao/centerdao"
	"admin100/app/dao/chargedao"
	"admin100/app/dao/gamedao"
	"admin100/app/model"
	"admin100/app/model/chargemodel"
	"admin100/app/service/centerservice"
	"admin100/library/define"
	"admin100/library/define/defErr"
	"admin100/library/utils"
	"admin100/library/utils/cnf"
	"fmt"
	"strconv"
	"strings"
	"time"

	"github.com/gogf/gf/frame/g"
	"github.com/gogf/gf/util/gconv"
)

var Charge = &chargeService{}

type chargeService struct{}

func (s *chargeService) GetDailyLTVListV1(req *model.DailyLTVReq) []*model.DailyLtv {
	if req.EndTime < req.StartTime {
		defErr.Panic(define.TimeErrStartEnd)
	}
	var (
		column        = dao.DailyLtv.Columns
		registerCount []*model.DailyRegisterPlayer
		realData      []*model.DailyLtv
	)

	m := dao.DailyLtv.WhereValNotEmpty(g.Map{
		column.PlatformId:                req.PlatformId,
		column.ServerId:                  req.ServerId,
		column.Channel:                   strings.Split(req.ChannelList, ","),
		column.Time + " between ? and ?": g.Slice{req.StartTime, req.EndTime},
	})

	m = m.Fields("server_id, platform_id, FROM_UNIXTIME(time, '%Y-%m-%d') as date, SUM(c1) As c1, SUM(c3) As c3, SUM(c7) As c7, SUM(c14) As c14, SUM(c30) As c30, SUM(c60) As c60, SUM(c90) As c90, SUM(c120) As c120")
	m.M = m.M.Order("date asc")
	data, err := m.Page(req.Cur, req.PNum).Group("date, " + column.ServerId + ", " + column.PlatformId).FindAll()
	if err != nil {
		defErr.Panic(define.DataOptFail, err.Error())
	}

	m2 := dao.DailyStatistics.WhereValNotEmpty(g.Map{
		column.PlatformId:                req.PlatformId,
		column.ServerId:                  req.ServerId,
		column.Channel:                   strings.Split(req.ChannelList, ","),
		column.Time + " between ? and ?": g.Slice{req.StartTime, req.EndTime},
	})
	m2 = m2.Fields("server_id, platform_id, FROM_UNIXTIME(time, '%Y-%m-%d') as date, SUM(create_role_count) as create_role, SUM(register_count) as register_role")
	if err = m2.Group("date, " + column.ServerId + ", " + column.PlatformId).Scan(&registerCount); err != nil {
		defErr.Panic(define.DataOptFail, err.Error())
	}

	for i := req.StartTime; i <= req.EndTime; i++ {
		i += 86399
		matchDate := time.Unix(int64(i), 0).Format("2006-01-02")

		realSingleData := model.DailyLtv{
			Time: int(i),
		}

		for _, v := range registerCount {
			if v.Date == matchDate {
				realSingleData.CreateRole = v.CreateRole
				realSingleData.RegisterRole = v.RegisterRole
			}
		}

		for _, e := range data {
			if e.Date == matchDate {
				realSingleData.C1 = e.C1
				realSingleData.C2 = e.C1
				realSingleData.C3 = e.C3
				realSingleData.C7 = e.C7
				realSingleData.C14 = e.C14
				realSingleData.C30 = e.C30
				realSingleData.C60 = e.C60
				realSingleData.C90 = e.C90
				realSingleData.C120 = e.C120
				if realSingleData.CreateRole > 0 {
					realSingleData.LTV1 = float32(e.C1) / float32(realSingleData.CreateRole)     // / exchangeRate
					realSingleData.LTV2 = float32(e.C2) / float32(realSingleData.CreateRole)     // / exchangeRate
					realSingleData.LTV3 = float32(e.C3) / float32(realSingleData.CreateRole)     // / exchangeRate
					realSingleData.LTV7 = float32(e.C7) / float32(realSingleData.CreateRole)     // / exchangeRate
					realSingleData.LTV14 = float32(e.C14) / float32(realSingleData.CreateRole)   // / exchangeRate
					realSingleData.LTV30 = float32(e.C30) / float32(realSingleData.CreateRole)   // / exchangeRate
					realSingleData.LTV60 = float32(e.C60) / float32(realSingleData.CreateRole)   // / exchangeRate
					realSingleData.LTV90 = float32(e.C90) / float32(realSingleData.CreateRole)   // / exchangeRate
					realSingleData.LTV120 = float32(e.C120) / float32(realSingleData.CreateRole) // / exchangeRate
				}
			}
		}

		realData = append(realData, &realSingleData)
	}

	return realData
}

type ChargeStatistics struct {
	PlatformId string `json:"platformId"`
	//ServerId                    string    `json:"serverId"`
	TodayCharge                      int `json:"todayCharge"`
	TodayChargePlayerCount           int `json:"todayChargePlayerCount"`
	YesterdayCharge                  int `json:"yesterdayCharge"`
	YesterdayChargePlayerCount       int `json:"yesterdayChargePlayerCount"`
	BeforeYesterdayCharge            int `json:"beforeYesterdayCharge"`
	BeforeYesterdayChargePlayerCount int `json:"beforeYesterdayChargePlayerCount"`

	ChargeData            []map[string]string `json:"chargeData"`
	ChargePlayerCountData []map[string]string `json:"chargePlayerCountData"`

	TodayChargeList           []string `json:"todayChargeList"`
	YesterdayChargeList       []string `json:"yesterdayChargeList"`
	BeforeYesterdayChargeList []string `json:"beforeYesterdayChargeList"`

	TodayChargePlayerCountList           []string `json:"todayChargePlayerCountList"`
	YesterdayChargePlayerCountList       []string `json:"yesterdayChargePlayerCountList"`
	BeforeYesterdayChargePlayerCountList []string `json:"beforeYesterdayChargePlayerCountList"`
}

func (s *chargeService) Statistics(platformId, serverId string, channelList []string) *ChargeStatistics {
	var (
		today          = utils.GetTodayZeroTimestamp()
		yestoday       = today - 86400
		beforeYestoday = yestoday - 86400
	)

	todayOnlineList, todayTotalCharge := TenMinuteStatistics.Get24hoursChargeCount(platformId, serverId, channelList, today)
	yesterdayOnlineList, yesterdayTotalCharge := TenMinuteStatistics.Get24hoursChargeCount(platformId, serverId, channelList, yestoday)
	beforeYesterdayOnlineList, beforeYesterdayTotalCharge := TenMinuteStatistics.Get24hoursChargeCount(platformId, serverId, channelList, beforeYestoday)
	todayChargePlayerCountList, todayChargePlayerCount := TenMinuteStatistics.Get24hoursChargePlayerCount(platformId, serverId, channelList, today)
	yesterdayChargePlayerCountList, yesterdayChargePlayerCount := TenMinuteStatistics.Get24hoursChargePlayerCount(platformId, serverId, channelList, yestoday)
	beforeYesterdayChargePlayerCountList, beforeYesterdayChargePlayerCount := TenMinuteStatistics.Get24hoursChargePlayerCount(platformId, serverId, channelList, beforeYestoday)

	chargeData := make([]map[string]string, 0, 144)
	for i := 0; i < 6*24; i = i + 1 {
		m := make(map[string]string, 4)
		m["时间"] = utils.FormatTime(i * 10 * 60)
		m["今日充值"] = utils.IfTrueStr(todayOnlineList[i] == "", "0", todayOnlineList[i])
		m["昨日充值"] = utils.IfTrueStr(yesterdayOnlineList[i] == "", "0", yesterdayOnlineList[i])
		m["前日充值"] = utils.IfTrueStr(beforeYesterdayOnlineList[i] == "", "0", beforeYesterdayOnlineList[i])
		chargeData = append(chargeData, m)
	}

	chargePlayerCountData := make([]map[string]string, 0, 144)
	for i := 0; i < 6*24; i = i + 1 {
		m := make(map[string]string, 4)
		m["时间"] = utils.FormatTime(i * 10 * 60)
		m["今日充值人数"] = utils.IfTrueStr(todayChargePlayerCountList[i] == "", "0", todayChargePlayerCountList[i])
		m["昨日充值人数"] = utils.IfTrueStr(yesterdayChargePlayerCountList[i] == "", "0", yesterdayChargePlayerCountList[i])
		m["前日充值人数"] = utils.IfTrueStr(beforeYesterdayChargePlayerCountList[i] == "", "0", beforeYesterdayChargePlayerCountList[i])
		chargePlayerCountData = append(chargePlayerCountData, m)
	}
	chargeStatistics := &ChargeStatistics{
		PlatformId:             platformId,
		TodayCharge:            todayTotalCharge,
		TodayChargePlayerCount: todayChargePlayerCount,
		//TodayCreateRole: GetCreateRoleCountByChannelList(gameDb, serverId, channelList, todayZeroTimestamp, todayZeroTimestamp+86400),
		YesterdayCharge:            yesterdayTotalCharge,
		YesterdayChargePlayerCount: yesterdayChargePlayerCount,
		//MaxOnlineCount:              GetMaxOnlineCount(node),
		BeforeYesterdayCharge:            beforeYesterdayTotalCharge,
		BeforeYesterdayChargePlayerCount: beforeYesterdayChargePlayerCount,

		TodayChargeList:           todayOnlineList,
		YesterdayChargeList:       yesterdayOnlineList,
		BeforeYesterdayChargeList: beforeYesterdayOnlineList,

		TodayChargePlayerCountList:           todayChargePlayerCountList,
		YesterdayChargePlayerCountList:       yesterdayChargePlayerCountList,
		BeforeYesterdayChargePlayerCountList: beforeYesterdayChargePlayerCountList,
		ChargeData:                           chargeData,
		ChargePlayerCountData:                chargePlayerCountData,
	}

	return chargeStatistics
}

func (s *chargeService) GetIncomeStatisticsChartData(req *model.DailyStatisticsReq) []map[string]string {
	today := utils.GetTodayZeroTimestamp()
	if req.EndTime > today {
		req.EndTime = today
	}
	if req.StartTime > today {
		req.StartTime = today
	}
	if req.EndTime < req.StartTime || req.StartTime == 0 {
		defErr.Panic(define.TimeErrStartEnd)
	}

	type dataType struct {
		ChargeCount     float32
		CreateRoleCount float32
		Time            int
	}
	var (
		data       = make([]*dataType, 0)
		column     = dao.DailyStatistics.Columns
		chargeData = make([]map[string]string, 0)
	)

	if err := dao.DailyStatistics.Fields("sum(" + column.TotalChargeMoney + ") as charge_count, time").
		WhereValNotEmpty(g.Map{
			column.PlatformId:                req.PlatformId,
			column.ServerId:                  req.ServerId,
			column.Channel:                   strings.Split(req.ChannelList, ","),
			column.Time + " between ? and ?": g.Slice{req.StartTime, req.EndTime},
		}).
		Group(column.Time).
		Scan(&data); err != nil {
		defErr.Panic(define.DataOptFail, err.Error())
	}

	for _, v := range data {
		m := map[string]string{
			"时间": utils.FormatDate(int64(v.Time)),
			"流水": strconv.Itoa(int(v.ChargeCount)),
		}
		chargeData = append(chargeData, m)
	}

	return chargeData
}

func (s *chargeService) GetChargeMoneyDistributionV1(req *model.ChargeMoneyDistributionReq) []*cnf.ChargeMoneyDistribution {
	var data = &ChargeLevelDistributionDataInDb{
		Count:   0,
		Level0:  0,
		Level1:  0,
		Level2:  0,
		Level3:  0,
		Level4:  0,
		Level5:  0,
		Level6:  0,
		Level7:  0,
		Level8:  0,
		Level9:  0,
		Level10: 0,
		Level11: 0,
		Level12: 0,
		Level13: 0,
	}
	var (
		matchData = cnf.FetchChargeMoneyDistCnf()
		m         = chargedao.PlayerChargeInfoRecord.Fields()
		column    = chargedao.PlayerChargeInfoRecord.Columns
		fields    = []string{}
		resData   = map[string]string{}
	)
	for k, v := range matchData {
		//todo model prepare
		fields = append(fields, fmt.Sprintf("IFNULL(SUM(if(total_money > %d and total_money <= %d, 1, 0)), 0) as level%d", v.Min, v.Max, k))
	}

	m = m.Fields("count(*) as count, " + strings.Join(fields, ","))
	if req.Promote != "" {
		accIds := centerdao.GlobalAccount.GetGlobalAccIdsByPromote(req.Promote)
		playerIds := centerdao.GlobalPlayer.GetGlobalIdsByAccIds(accIds)
		if len(playerIds) > 0 {
			m = m.Where(column.PartId+" in (?)", playerIds)
		}
	}

	if req.ServerId != "" {
		m.Where(column.ServerId, req.ServerId)
	}
	if err := m.Scan(&data); err != nil {
		defErr.Panic(define.DataOptFail, err.Error())
	}

	resData = gconv.MapStrStr(data)
	for k, v := range resData {
		if k == "Count" {
			continue
		}
		order := gconv.Int(strings.ReplaceAll(k, "Level", ""))
		if order < len(matchData) {
			matchData[order].Count = gconv.Int(v)
			if data.Count > 9 {
				matchData[order].Rate = float32(matchData[order].Count) / gconv.Float32(v) * 100
			}
		}
	}

	return matchData
}

type ChargeLevelDistributionDataInDb struct {
	Count   int
	Level0  int
	Level1  int
	Level2  int
	Level3  int
	Level4  int
	Level5  int
	Level6  int
	Level7  int
	Level8  int
	Level9  int
	Level10 int
	Level11 int
	Level12 int
	Level13 int
	Level14 int
	Level15 int
	Level16 int
	Level17 int
	Level18 int
	Level19 int
	Level20 int
	Level21 int
	Level22 int
	Level23 int
	Level24 int
	Level25 int
}

type ChargeActivityDistribution struct {
	ChargeItemId int     `json:"chargeItemId"`
	Count        int     `json:"count"`
	Rate         float32 `json:"rate"`
	Money        float32 `json:"money"`
	MoneyRate    float32 `json:"moneyRate"`
}

func (s *chargeService) GetChargeActivityDistribution(req *model.ChargeActivityDistributionReq) []*ChargeActivityDistribution {
	var (
		data   = []*ChargeActivityDistribution{}
		column = chargedao.ChargeInfoRecord.Columns
	)

	m := chargedao.ChargeInfoRecord.Fields("charge_item_id, count(*) as count, sum(money) as money")

	if req.IsFirst == 1 {
		m = m.Where(column.IsFirst, 1)
	}

	if req.Promote != "" {
		accIdList := centerdao.GlobalAccount.GetGlobalAccIdsByPromote(req.Promote)
		if len(accIdList) > 0 {
			m = m.Where(column.AccId, accIdList)
		} else {
			return data
		}
	}

	if err := m.WhereValNotEmpty(g.Map{
		column.PartId:     req.PlatformId,
		column.ServerId:   req.ServerId,
		column.ChargeType: 99,
		column.Channel:    strings.Split(req.ChannelList, ","),
	}).Group(column.ChargeItemId).Scan(&data); err != nil {
		defErr.Panic(define.DataOptFail, err.Error())
	}

	sum := 0
	var moneySum float32
	for _, e := range data {
		sum += e.Count
		moneySum += e.Money
	}
	if sum > 0 {
		for _, e := range data {
			e.Rate = float32(e.Count) / float32(sum) * 100
		}
	}
	if moneySum > 0 {
		for _, e := range data {
			e.MoneyRate = float32(e.Money) / float32(moneySum) * 100
		}
	}

	return data
}

type ChargeTaskDistribution struct {
	TaskId int     `json:"taskId"`
	Count  int     `json:"count"`
	Rate   float32 `json:"rate"`
}

func (s *chargeService) GetChargeTaskDistribution(req *model.ChargeTaskDistributionReq) []*ChargeTaskDistribution {
	var (
		data   = []*ChargeTaskDistribution{}
		column = chargedao.ChargeInfoRecord.Columns
	)

	m := chargedao.ChargeInfoRecord.Fields("curr_task_id as task_id, count(*) as count")

	if req.IsFirst == 1 {
		m = m.Where(column.IsFirst, 1)
	}

	if req.Promote != "" {
		accIdList := centerdao.GlobalAccount.GetGlobalAccIdsByPromote(req.Promote)
		if len(accIdList) > 0 {
			m = m.Where(column.AccId, accIdList)
		} else {
			return data
		}
	}

	if err := m.WhereValNotEmpty(g.Map{
		column.PartId:     req.PlatformId,
		column.ServerId:   req.ServerId,
		column.ChargeType: 99,
		column.Channel:    strings.Split(req.ChannelList, ","),
	}).Group("task_id").Scan(&data); err != nil {
		defErr.Panic(define.DataOptFail, err.Error())
	}

	sum := 0
	for _, e := range data {
		sum += e.Count
	}
	if sum > 0 {
		for _, e := range data {
			e.Rate = float32(e.Count) / float32(sum) * 100
		}
	}

	return data
}

func (s *chargeService) GetChargeLevelDistributionV1(req *model.ChargeLevelDistributionReq) []*cnf.ChargeLevelDistributionV1 {
	var data = &ChargeLevelDistributionDataInDb{
		Count:   0,
		Level0:  0,
		Level1:  0,
		Level2:  0,
		Level3:  0,
		Level4:  0,
		Level5:  0,
		Level6:  0,
		Level7:  0,
		Level8:  0,
		Level9:  0,
		Level10: 0,
		Level11: 0,
		Level12: 0,
		Level13: 0,
		Level14: 0,
		Level15: 0,
		Level16: 0,
		Level17: 0,
		Level18: 0,
		Level19: 0,
		Level20: 0,
		Level21: 0,
		Level22: 0,
		Level23: 0,
		Level24: 0,
		Level25: 0,
	}
	var (
		matchData = cnf.FetchChargeLevelMoneyCnf()
		m         = chargedao.ChargeInfoRecord.Fields("")
		column    = chargedao.ChargeInfoRecord.Columns
		fields    = []string{}
		resData   = map[string]string{}
	)
	for k, v := range matchData {
		fields = append(fields, fmt.Sprintf("IFNULL(SUM(if(curr_level >= %d and curr_level <= %d, 1, 0)), 0) as level%d", v.Min, v.Max, k))
	}
	m = m.Fields("count(*) as count, " + strings.Join(fields, ","))

	if req.IsFirst == 1 {
		m = m.Where(column.IsFirst, req.IsFirst)
	}
	if req.Promote != "" {
		accIdList := centerdao.GlobalAccount.GetGlobalAccIdsByPromote(req.Promote)
		if len(accIdList) > 0 {
			m = m.Where(column.AccId+" in (?)", accIdList)
		}
	}
	if req.ServerId != "" {
		m.Where(column.ServerId, req.ServerId)
	}
	if err := m.Fields().Scan(&data); err != nil {
		defErr.Panic(define.DataOptFail, err.Error())
	}

	resData = gconv.MapStrStr(data)
	for k, v := range resData {
		if k == "Count" {
			continue
		}
		order := gconv.Int(strings.ReplaceAll(k, "Level", ""))
		if order < len(matchData) {
			matchData[order].Count = gconv.Int(v)
		}
	}

	return matchData
}

func (s *chargeService) GetChargeRankList(req *model.ChargeRankReq) ([]*chargemodel.PlayerChargeInfoRecord, int) {

	var (
		column = chargedao.PlayerChargeInfoRecord.Columns
		total  = 0
	)
	m := chargedao.PlayerChargeInfoRecord.Where(g.Map{
		column.PartId:                          req.PlatformId,
		column.ServerId:                        req.ServerId,
		column.Channel:                         strings.Split(req.ChannelList, ","),
		column.RecordTime + " between ? and ?": g.Slice{req.StartTime, req.EndTime},
	})
	m = m.Where(column.ChargeCount + " > 0")

	m1 := m.Clone()
	data, err := m.Page(req.Cur, req.PNum).FindAll()
	if err != nil {
		defErr.Panic(define.DataOptFail, err.Error())
	}
	total, err = m1.Count()
	if err != nil {
		defErr.Panic(define.DataOptFail, err.Error())
	}

	for _, e := range data {
		sNode := centerservice.CGameServer.FetchNodeStrByPtIdAndSid(e.PartId, e.ServerId)
		gm := gamedao.NewPlayerDao(sNode)
		player, err := gm.Where(gm.Columns.Id, e.PlayerId).FindOne()
		if err != nil {
			continue
		}

		e.PlayerName = player.ServerId + "." + player.Nickname
		e.Account = player.AccId
		e.LastLoginTime = player.LastLoginTime
		e.RegisterTime = player.RegTime

		//TotalMoney, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", e.TotalMoney/exchangeRate), 64)
		TotalMoney, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", e.TotalMoney), 64)
		e.TotalMoney = float64(TotalMoney)

		//MaxMoney, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", e.MaxMoney/exchangeRate), 64)
		MaxMoney, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", e.MaxMoney), 64)
		e.MaxMoney = float64(MaxMoney)

		//MinMoney, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", e.MinMoney/exchangeRate), 64)
		MinMoney, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", e.MinMoney), 64)
		e.MinMoney = float64(MinMoney)
	}

	if data == nil {
		data = []*chargemodel.PlayerChargeInfoRecord{}
	}
	return data, total
}
